package com.gitee.wsl.ext.array.bytes

import com.gitee.wsl.ext.array.toByteArray
import com.gitee.wsl.ext.collection.fill
import com.gitee.wsl.lang.ByteOrder

@OptIn(ExperimentalUnsignedTypes::class)
fun Int.toUByteArray(): UByteArray {
    val bytes = UByteArray(4)
    (0..3).forEach { i -> bytes[bytes.size - 1 - i] = (this shr (i * 8)).toUByte() }
    return bytes
}

/**
 * @return the integer as a byte array in little endian format
 */
//fun Int.toByteArray(): ByteArray = byteArrayOf(
//    this.toByte(),
//    (this ushr 8).toByte(),
//    (this ushr 16).toByte(),
//    (this ushr 24).toByte(),
//)
fun Int.toByteArray(byteOrder: ByteOrder = ByteOrder.BigEndian): ByteArray{
    val bytes = ByteArray(Int.SIZE_BYTES)
    toByteArray(bytes,byteOrder,0)
    return bytes
}

fun Int.toByteArray(byteArray: ByteArray,byteOrder: ByteOrder= ByteOrder.BigEndian,startIndex:Int=0){
    byteArray.updateUseLittleEndian(byteOrder,startIndex,Int.SIZE_BYTES){
        (this ushr 8*it).toByte()
    }
}

/**
 * @return an integer from a byte array in little endian format
 */
//fun ByteArray.toInt(): Int
//{
//    var int = 0
//    forEachIndexed { index, byte -> int = int or (byte.toUByte().toInt() shl 8 * index) }
//    return int
//}
fun ByteArray.toInt(order: ByteOrder = ByteOrder.BigEndian,startIndex: Int = 0): Int
{
    var value = 0
    getUseLittleEndian(order,startIndex,Int.SIZE_BYTES) { index, byte -> value = value or (byte.toUByte().toInt() shl 8 * index) }
    return value
}

/**
 * Take the first [take] number of bytes and fill the byte array to meet the [capacity].
 * @return an integer as a byte array in little endian format
 */
fun Int.toByteArray(take: Int, capacity: Int,byteOrder: ByteOrder= ByteOrder.BigEndian): ByteArray
{
    val bytes = this.toByteArray(byteOrder).take(take).toMutableList()

    // Fill the remaining slots with zero.
    return bytes.fill(capacity) { 0 }.toByteArray()
}

/**
 * Converts the first 4 bytes into their integer representation following the big-endian conversion.
 * @throws NumberFormatException if the array size is less than 4
 */
fun Array<Byte>.toInt(): Int {
    if (this.size < 4) throw NumberFormatException("The array size is less than 4")
    return (this[0].toUByte().toInt() shl 24) + (this[1].toUByte().toInt() shl 16) + (this[2].toUByte().toInt() shl 8) + (this[3].toUByte().toInt() shl 0)
}

